﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace ZYO
{
    ///<summary>
    ///This class provides helper functions for frequent operations performed
    ///on Xml stuff
    ///</summary>
    public class XmlHelper
    {
        /// <summary>
        /// Remove the CDATA section from ResultParameterVal if present.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string RemoveCDATASection(string input)
        {
            string output = String.Empty;
            try
            {
                string paramValXml = "<XmlHelperRoot>" +
                    input +
                    "</XmlHelperRoot>";
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(paramValXml);
                XmlElement root = doc.DocumentElement;

                if (root.FirstChild != null)
                {
                    output = root.FirstChild.InnerXml;
                }
            }
            catch (XmlException exception)
            {
                Trace.Write(exception.Message);

            }
            return output;

        }

        private static Regex XmlDecl = new Regex(@"\<\?xml\s+version[^\>]+\?\>\s+", RegexOptions.IgnoreCase);
        /// <summary>
        /// Remove the CDATA section from ResultParameterVal if present.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string RemoveXmlDecl(string input)
        {
            return XmlDecl.Replace(input, string.Empty);
        }

        /// <summary>
        /// Deletes an attribute element if it exists.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="attribName"></param>
        public static void DeleteAttributeNode(XmlElement element, string attributeName)
        {
            if (element.HasAttribute(attributeName))
            {
                element.Attributes.RemoveNamedItem(attributeName);
            }
        }

        /// <summary>
        ///    Appends a new element.
        /// </summary>
        /// <param name="parentElement">Parent element to append new element to.</param>
        /// <param name="tagName">Tag name of new element.</param>
        /// <returns>New element.</returns>
        public static XmlElement AppendElement(XmlElement parentElement, string tagName)
        {
            return AppendElement(parentElement, tagName, string.Empty);
        }

        /// <summary>
        ///    Appends a new element onto the parent element.
        /// </summary>
        /// <param name="parentElement">
        ///    Element to append child to.
        /// </param>
        /// <param name="tagName">
        ///    Tag name of new element.
        /// </param>
        /// <param name="elementValue">
        ///    Initial element value.
        /// </param>
        /// <returns>
        ///    Element created.
        /// </returns>
        public static XmlElement AppendElement(XmlElement parentElement, string tagName, string elementValue)
        {
            XmlElement newElement = parentElement.OwnerDocument.CreateElement(tagName);
            newElement.InnerXml = elementValue;
            parentElement.AppendChild(newElement);
            return newElement;
        }

        ///<summary>
        ///Translates the contents of an xml node into a boolean.  If the node
        ///is null or can't be parsed, false is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        public static bool NodeToBoolean(XmlNode n)
        {
            return XmlHelper.NodeToBoolean(n, false);
        }

        ///<summary>
        ///Translates the contents of an xml node into a boolean.  If the node
        ///is null or can't be parsed, dafultValue is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        ///<param name="defaultValue">value to return if node is null or can't be parsed</param>
        public static bool NodeToBoolean(XmlNode n, bool defaultValue)
        {
            bool returnValue;

            if (n == null)
            {
                returnValue = defaultValue;
            }
            else
            {
                string nodeValue = n.InnerText;
                if (String.Compare(nodeValue, "yes", true) == 0 ||
                    String.Compare(nodeValue, "1", true) == 0 ||
                    String.Compare(nodeValue, "true", true) == 0)
                {
                    returnValue = true;
                }
                else if (String.Compare(nodeValue, "no", true) == 0 ||
                          String.Compare(nodeValue, "0", true) == 0 ||
                          String.Compare(nodeValue, "false", true) == 0)
                {
                    returnValue = false;
                }
                else
                {
                    returnValue = defaultValue;
                }
            }
            return returnValue;
        }
        ///<summary>
        ///Translates the contents of an xml node into a boolean.  If the node
        ///is null or can't be parsed, the empty string is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        public static string NodeToString(XmlNode n)
        {
            return XmlHelper.NodeToString(n, String.Empty);
        }
        ///<summary>
        ///Translates the contents of an xml node into a string.  If the node
        ///is null or can't be parsed, dafultValue is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        ///<param name="defaultValue">value to return if node is null or can't be parsed</param>
        public static string NodeToString(XmlNode n, string defaultValue)
        {
            string returnValue;

            if (n == null)
            {
                returnValue = defaultValue;
            }
            else
            {
                returnValue = n.InnerText;
            }
            return returnValue;
        }

        ///<summary>
        ///   Translates the contents of an xml node into a integer.  If the node
        ///   is null or can't be parsed, the 0 is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        public static int NodeToInt(XmlNode n)
        {
            return XmlHelper.NodeToInt(n, 0);
        }

        ///<summary>
        ///   Translates the contents of an xml node into a integer.  If the node
        ///   is null or can't be parsed, the default is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        ///<param name="defaultValue">Default value if node can't be parsed</param>
        public static int NodeToInt(XmlNode n, int defaultValue)
        {
            int returnValue;
            if (n == null || n.InnerText == "")
            {
                returnValue = defaultValue;
            }
            else
            {
                returnValue = Int32.Parse(n.InnerText);
            }
            return returnValue;
        }

        /// <summary>
        ///    Converts node to Int64 number.
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public static Int64 NodeToInt64(XmlNode n)
        {
            return NodeToInt(n, 0);
        }

        /// <summary>
        ///    Converts node to Int64 number.  Returns default value if
        ///    node does not exist.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Int64 NodeToInt64(XmlNode n, Int64 defaultValue)
        {
            Int64 returnValue;
            if (n == null || n.InnerText == "")
            {
                returnValue = defaultValue;
            }
            else
            {
                returnValue = Int64.Parse(n.InnerText);
            }
            return returnValue;
        }

        ///<summary>
        ///   Translates the contents of an xml node into a guid.  If the node
        ///   is null or can't be parsed, the null is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        public static Guid NodeToGuid(XmlNode n)
        {
            return XmlHelper.NodeToGuid(n, Guid.Empty);
        }

        ///<summary>
        ///   Translates the contents of an xml node into a guid.  If the node
        ///   is null or can't be parsed, the default is returned.
        ///</summary>
        ///<param name="n">Xml node to convert</param>
        ///<param name="defaultValue">Default value if node can't be parsed</param>
        public static Guid NodeToGuid(XmlNode n, Guid defaultValue)
        {
            Guid returnValue;
            if (n == null || n.InnerText == "")
            {
                returnValue = defaultValue;
            }
            else
            {
                returnValue = new Guid(n.InnerText);
            }
            return returnValue;
        }

        ///<summary></summary>
        public static void DoTransform(XmlDocument doc, string styleSheetString, string outputFile)
        {
            TextWriter writer = new StreamWriter(outputFile);
            try
            {
                DoTransform(doc, styleSheetString, writer);
            }
            finally
            {
                if (writer != null)
                    writer.Close();
            }
        }

        ///<summary>
        /// Takes a style sheet and an XML Document and transforms the document writing
        /// the output into a file
        ///</summary>
        ///<param name="doc">Xml document to transform</param>
        ///<param name="styleSheetString">Style sheet to use for transformation</param>
        ///<param name="outputWriter">Text writer used to write the output</param>
        public static void DoTransform(XmlDocument doc, string styleSheetString, TextWriter outputWriter)
        {
#if EVERETT
            XslTransform styleSheet = new XslTransform() ;
			Evidence evidence = new Evidence() ;
			evidence.AddHost( new Zone(SecurityZone.MyComputer) );
			styleSheet.Load( 
				new XPathDocument(new StringReader(styleSheetString)), 
				new XmlUrlResolver(),
				evidence) ;
			styleSheet.Transform( doc, null, outputWriter, null) ;
#else
            XslCompiledTransform transform = new XslCompiledTransform();
            transform.Load(new XmlTextReader(new StringReader(styleSheetString)), XsltSettings.TrustedXslt, null);
            transform.Transform(doc, null, outputWriter);
#endif
        }

        /// <summary>
        ///    If the attribute exists it returns the attribute object.  Otherwise
        ///    the attribute is created and added to the elements attributes and then
        ///    returned.
        /// </summary>
        public static XmlAttribute GetOrCreateAttribute(XmlElement e, string attributeName)
        {
            return GetOrCreateAttribute(e, attributeName, String.Empty);
        }

        /// <summary>
        ///		Grabs an attribute from the Attributes array; if not found, then returns null.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="strAttributeName"></param>
        /// <returns></returns>
        public static string GetAttributeValueFromNode(XmlNode n, string strAttributeName)
        {
            XmlAttribute a = n.Attributes[strAttributeName];
            return (null == a) ? null : a.Value;
        }

        /// <summary>
        ///    If the attribute exists it returns the attribute object.  Otherwise
        ///    the attribute is created and added to the elements attributes and then
        ///    returned.
        /// </summary>
        public static XmlAttribute GetOrCreateAttribute(XmlElement e, string attributeName, string initialValue)
        {
            XmlAttribute returnAttribute;
            returnAttribute = e.Attributes[attributeName];
            if (returnAttribute == null)
            {
                returnAttribute = e.OwnerDocument.CreateAttribute(attributeName);
                returnAttribute.InnerText = initialValue;
                e.SetAttributeNode(returnAttribute);
            }
            return returnAttribute;
        }

        /// <summary>
        ///    If the element exists it returns the element object.  Otherwise
        ///    the element is created and added to the element and then
        ///    returned.
        /// </summary>
        public static XmlElement GetOrCreateElement(XmlElement e, string elementName)
        {
            return GetOrCreateElement(e, elementName, String.Empty);
        }

        /// <summary>
        ///    If the element exists it returns the element object.  Otherwise
        ///    the element is created the text is set to initialValue 
        ///    and added to the element and then returned.
        /// </summary>
        public static XmlElement GetOrCreateElement(XmlElement e, string elementName, string initialValue)
        {
            XmlElement returnElement;
            returnElement = e[elementName];
            if (returnElement == null)
            {
                returnElement = CreateElement(e, elementName, initialValue);
            }
            return returnElement;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static XmlElement CreateElement(XmlElement e, string elementName)
        {
            return CreateElement(e, elementName, String.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        /// <param name="elementName"></param>
        /// <param name="initialValue"></param>
        /// <returns></returns>
        public static XmlElement CreateElement(XmlElement e, string elementName, string initialValue)
        {
            XmlElement returnElement;

            returnElement = e.OwnerDocument.CreateElement(elementName);
            returnElement.InnerText = initialValue;
            e.AppendChild(returnElement);

            return returnElement;
        }

        /// <summary>
        ///		Removes formatting from a string.
        /// </summary>
        /// <param name="strXmlDoc"></param>
        /// <returns></returns>
        public static string UnFormatXml(string strXmlDoc)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(strXmlDoc);
                return UnFormatXml(doc);
            }
            catch (Exception)
            {
                return strXmlDoc;
            }
        }

        /// <summary>
        ///		Removes formatting from an XML document.
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static string UnFormatXml(XmlDocument doc)
        {
            StringBuilder sb = new StringBuilder();
            XmlTextWriter xtwWriter = new XmlTextWriter(new StringWriter(sb));

            //	Begin writing the result.
            //
            xtwWriter.Formatting = Formatting.None;
            xtwWriter.Indentation = 0;
            doc.PreserveWhitespace = false;

            doc.WriteTo(xtwWriter);
            return sb.ToString();
        }


        /// <summary>
        ///		Adds XML formatting to an XML document.
        /// </summary>
        /// <param name="strXmlDoc"></param>
        /// <returns></returns>
        public static string FormatXml(String strXmlDoc)
        {
            return FormatXml(strXmlDoc, 2);
        }

        /// <summary>
        ///		Adds XML formatting to an XML document.
        /// </summary>
        /// <param name="strXmlDoc"></param>
        /// <param name="indentWidth"></param>
        /// <returns></returns>
        public static string FormatXml(string strXmlDoc, int indentWidth)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(strXmlDoc);
                return FormatXml(doc, indentWidth);
            }
            catch (Exception)
            {
                return strXmlDoc;
            }
        }

        /// <summary>
        ///		Adds xml formatting to document.
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static string FormatXml(XmlDocument doc)
        {
            return FormatXml(doc, 2);
        }

        /// <summary>
        ///		Adds xml formatting to document.
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="indentWidth"></param>
        /// <returns></returns>
        public static string FormatXml(XmlDocument doc, int indentWidth)
        {
            StringBuilder sb = new StringBuilder();
            XmlTextWriter xtwWriter = new XmlTextWriter(new StringWriter(sb));

            //	Begin writing the result.
            //
            xtwWriter.Formatting = Formatting.Indented;
            xtwWriter.Indentation = indentWidth;
            doc.PreserveWhitespace = false;

            doc.WriteTo(xtwWriter);
            return sb.ToString();
        }

        //
        // TODO: Provide a method to create a xml fragment without having to pass in a "owner"
        // document or way to get the owner document.  Suggested implmenetation would be to have
        // a static XmlDocument attached to the XmlHelper class that can be used with the CreateDocumentFragment()
        // call.
        //

        /// <summary>
        ///    Converts an xml contained in a string to an xml node.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static XmlNode StringToXml(string xml, XmlNode node)
        {
            return StringToXml(xml, node.OwnerDocument);
        }

        /// <summary>
        ///    Converts an xml contained in a string to an xml node.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="document"></param>
        /// <returns></returns>
        public static XmlNode StringToXml(string xml, XmlDocument document)
        {
            XmlDocumentFragment fragment = document.CreateDocumentFragment();
            fragment.InnerXml = xml;
            return fragment.FirstChild;
        }

        private static string Serialize(Object SerializableObject, XmlSerializer x)
        {
            StringBuilder xml = new StringBuilder();
            TextWriter writer = new StringWriter(xml);
            NonDeclXmlTextWriter nonDeclWriter = new NonDeclXmlTextWriter(writer);
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(string.Empty, string.Empty);
            x.Serialize(nonDeclWriter, SerializableObject, ns);
            return xml.ToString();
        }

        public static string Serialize(Object SerializableObject)
        {
            XmlSerializer x = new XmlSerializer(SerializableObject.GetType());
            return Serialize(SerializableObject, x);
        }

        public static string Serialize(Object SerializableObject, string RootElementName)
        {
            // Create an XmlRootAttribute, and set its properties.
            XmlRootAttribute xRoot = new XmlRootAttribute();
            xRoot.ElementName = RootElementName;
            XmlSerializer x = new XmlSerializer(SerializableObject.GetType(), xRoot);
            return Serialize(SerializableObject, x);
        }

        public static void Serialize2File(Object SerializableObject, string FileName)
        {
            XmlSerializer x = new XmlSerializer(SerializableObject.GetType());
            XmlTextWriter xmlTextWriter = new XmlTextWriter(FileName, Encoding.Default);
            x.Serialize(xmlTextWriter, SerializableObject);
            xmlTextWriter.Flush();
            xmlTextWriter.Close();
            return;
        }

        public static T DeSerialize<T>(string xml) where T : class
        {
            return DeSerialize(xml, typeof(T)) as T;
        }

        public static Object DeSerialize(string xml, Type targetType)
        {
            XmlSerializer x = new XmlSerializer(targetType);
            TextReader reader = new StringReader(xml);
            return x.Deserialize(reader);
        }

        internal class NonDeclXmlTextWriter : System.Xml.XmlTextWriter
        {
            public NonDeclXmlTextWriter(System.IO.TextWriter w) : base(w) { }
            public override void WriteStartDocument() { }
            public override void WriteStartDocument(bool standalone) { }
        }


    } // end class

}
